#pragma warning( disable: 4786 )
#include <vector>
#include "goldbeardguts.h"


class GBInfo
{
	public:
		uint8 m_reel;
		uint8 m_position;
		GBInfo(uint8 reel, uint8 position)
		{
			m_reel = reel;
			m_position = position;
		}
};

typedef vector<GBInfo> GbList;

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldbeardGuts::GoldbeardGuts()
///
/// This is the default constructor for the class.
////////////////////////////////////////////////////////////////////////////
GoldbeardGuts::GoldbeardGuts()
{
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldbeardGuts::classifyStops()
///
/// @param   stops      The array of stop positions for the line.
/// @param   bet        The value of the line bet.
/// @param   line       The index of the line.
///
/// @return	 uint8      A payout from the SpinResult enumeration as a uint8.
///
/// This helper method is used to calculate the payout on a line.
////////////////////////////////////////////////////////////////////////////
void
GoldbeardGuts::classifyStops(SpinLine* spinline, uint8* stops,uint8 bet, uint8 line, uint8& rtnresult, uint8& multiplier)
{
	SpinResult result            = EVT_LOSER; // spin result :)
	uint8      testIcon          = BLANK;     // Icon at current position
	uint8      iconThatIsNotGoldb = BLANK;     // Holder for an Icon that is NOT cleopatra
	uint8      goldbCount         = 0;	      // Has a WILD icon (a cleopatra icon) in the sequence
    bool8      bFirstIconIsGoldb  = false;     // Cleo in the first spot means it can stand alone OR substitute
	bool8		freeSpin		 = false;

    // By default everything pays at a x1 multiplier
    multiplier = 1;

	freeSpin = (getGameModeId() == MODE_FREE_SPIN);

	//Now, go through the rest, until the streak is over
	for ( uint8 i = 0; (i < getReelCount()); i++ )
    {
		testIcon = getIcon(getGameModeId(), i, stops[i])->iconid;

        // Check to see if it is cleo (we bump the count and continue looking)
        if ( testIcon == GOLDBEARD )
        {
            if ( i == 0 )
            {
                bFirstIconIsGoldb = true;
            }

            if ( iconThatIsNotGoldb == BLANK )
            {
                goldbCount++;
            }
            else
            {
                goldbCount = 1;
            }
        }
        // Coins don't pay on individual lines, 
        // just as scatters.
        else if ( testIcon == COIN )
        {
            break;
        }
        else
        {
            // If we haven't found our first non goldbeard icon, store it off.
            if ( iconThatIsNotGoldb == BLANK )
            {
                iconThatIsNotGoldb = testIcon;
            }
            // If we have found our fist non cleo icon, and this icon was not cleo
            // or pyramid (those were checked above) and it is not the same as
            // the first non cleo icon, then our evaluation stops.
            else if ( iconThatIsNotGoldb != testIcon )
            {
                break;
            }
        }
    }

	//All other Icons EVAL
	switch(iconThatIsNotGoldb)
	{
		case GALLEON:
			if ( i == 5 )
			{
                result = EVT_FIVE_GALLEON;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_GALLEON;
			}
			else if (i == 3)
            {
                result = EVT_THREE_GALLEON;
			}
			else if (i == 2)
            {
                result = EVT_TWO_GALLEON;
			}
			break;

		case PARROT:
			if ( i == 5 )
			{
                result = EVT_FIVE_PARROT;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_PARROT;
			}
			else if (i == 3)
            {
                result = EVT_THREE_PARROT;
			}
			else if (i == 2)
            {
                result = EVT_TWO_PARROT;
			}
			break;

        case CANNON:
			if ( i == 5 )
			{
                result = EVT_FIVE_CANNON;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_CANNON;
			}
			else if (i == 3)
            {
                result = EVT_THREE_CANNON;
			}
			else if (i == 2)
            {
                result = EVT_TWO_CANNON;
			}
			break;

        case TREASURE_CHEST:
			if ( i == 5 )
			{
                result = EVT_FIVE_TREASURE_CHEST;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_TREASURE_CHEST;
			}
			else if (i == 3)
            {
                result = EVT_THREE_TREASURE_CHEST;
			}
			else if (i == 2)
            {
                result = EVT_TWO_TREASURE_CHEST;
			}			
            break;		
		
        case ACE:
			if ( i == 5 )
			{
                result = EVT_FIVE_ACE;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_ACE;
			}
			else if (i == 3)
            {
                result = EVT_THREE_ACE;
			}
			break;

        case KING:
			if ( i == 5 )
			{
                result = EVT_FIVE_KING;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_KING;
			}
			else if (i == 3)
            {
                result = EVT_THREE_KING;
			}
            break;

        case QUEEN:
			if ( i == 5 )
			{
                result = EVT_FIVE_QUEEN;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_QUEEN;
			}
			else if (i == 3)
            {
                result = EVT_THREE_QUEEN;
			}
			break;

        case JACK:
			if ( i == 5 )
			{
                result = EVT_FIVE_JACK;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_JACK;
			}
			else if (i == 3)
            {
                result = EVT_THREE_JACK;
			}
			break;

        case TEN:
			if ( i == 5 )
			{
                result = EVT_FIVE_TEN;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_TEN;
			}
			else if (i == 3)
            {
                result = EVT_THREE_TEN;
			}
			break;

        case NINE:
			if ( i == 5 )
			{
                result = EVT_FIVE_NINE;
			}
			else if (i == 4)
            {
                result = EVT_FOUR_NINE;
			}
			else if (i == 3)
            {
                result = EVT_THREE_NINE;
			}

			break;

        // Coin and Blanks don't pay.
        case COIN:
        case BLANK:
            break;
        
        // Some unknown symbol is on the reel!
        default:
            ASSERT(false);
            break;
	}

    if ( result > EVT_LOSER && goldbCount > 0 )
    {
        multiplier = MULTIPLIER_GOLDB_SUBSTITUTE;
    }
	else
	{
		// Check the cae of just one Goldbeard on wheel 1
		if (bFirstIconIsGoldb && result == EVT_LOSER)
			result = EVT_ONE_GOLDBEARD;
	}

    if ( multiplier == MULTIPLIER_GOLDB_SUBSTITUTE )
    {
        spinline->addNote(NOTE_GOLDB_SUBSTITUTION_2X);
    }

    rtnresult = (uint8) result;	

}



////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldbeardGuts::classifyScatters()
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This is an override of the framework method.
/// It determines if the current spin merits free spins or scatter payments.
////////////////////////////////////////////////////////////////////////////
void
GoldbeardGuts::classifyScatters(SlotSpin *spin)
{

	uint8 numScatterIcons = 0;
    int32 scatterPositions = 0;
	uint8 stop = 0;
	uint8 whichItem = BLANK;
    uint8 position = 0;
    uint8 multiplier = ( getGameModeId() == MODE_FREE_SPIN )  ? MULTIPLIER_FREE_SPIN : 1;
	bool8 gbReel0Counted = false;
	bool8 gbReel4Counted = false;
	GbList list;

	spin->clearScatters();

	// if we are in the first paid spin (NOT a bonus spin) try for the Random Progressive Jackpot
	if (getGameModeId() == MODE_NORMAL ) 
	{
		if ( getRandomProgressiveJackpotResult(spin->getSpinLineCount()) ||
			 m_bForceRandomJackpot)
        {
	        spin->addScatter( 0, 
                              getPayout(EVT_RANDOM_PROGRESSIVE_WINNER)->payoutAmount, 
                              1,
                              true,
                              EVT_RANDOM_PROGRESSIVE_WINNER,
                              0 );
        }
    }

	for(int row = 0; row < 3; row++)
	{

  		for(int reel = 0; reel<5; reel++)
		{
			stop = relativeWheelPosition(getGameModeId(), reel, spin->getStops()[reel], row);
			whichItem = getIcon(getGameModeId(), reel, stop)->iconid;

			// Lets count the number of Goldbeards visible, only 1 per reel counts
			if (reel == 0 && whichItem == GOLDBEARD)
			{
				GBInfo gbi(0,row);
				list.push_back(gbi);
				gbReel0Counted = true;
			}
			if (reel == 4 && whichItem == GOLDBEARD)
			{
				GBInfo gbi(4,row);
				list.push_back(gbi);
				gbReel4Counted = true;
			}
			
			if ( whichItem == COIN )
			{
				numScatterIcons++;
                scatterPositions += 1<<position;
            }

            position++;
		} // reel

	} // row

	if (numScatterIcons >= 1 )
    {
        uint8 payouttypeid = EVT_SCATTER_NEAR_MISS;

	    switch ( numScatterIcons )
	    {
	       case 1:
                payouttypeid = EVT_SCATTER_NEAR_MISS;
                break;
           case 2: 
                payouttypeid = EVT_TWO_COIN;
                break;
	       case 3: 
                payouttypeid = EVT_THREE_COIN;
                break;
	       case 4: 
                payouttypeid = EVT_FOUR_COIN;
                break;
           case 5: 
                payouttypeid = EVT_FIVE_COIN;
                break;
	    };

        int32 nPayout = getPayout(payouttypeid)->payoutAmount * ( spin->getSpinLineCount());

        increaseTotalWin(nPayout*multiplier);

	    SlotScatter* pScatter = spin->addScatter( scatterPositions, 
                                                  nPayout*getBetPerLine(),
                                                  multiplier,
                                                  false,
                                                  payouttypeid,
                                                  0 );

		// add the free spin only when in free spin mode
		if (getGameModeId() == MODE_FREE_SPIN ) 
        {
            pScatter->addNote(NOTE_FREE_SPIN_3X);
        }
   
    }

	// If we have at least one Goldbeard in reel 0 and reel4 then we are in free spin mode.
	if (gbReel0Counted && gbReel4Counted)
    {
		GbList::iterator gbit;

		gbit = list.begin();
		while (gbit != list.end())
		{
			int32 spinCount;
			GBInfo* info;

			info = &*gbit;
			spinCount = getFreeSpins();
			scatterPositions = 1<<(info->m_reel + (info->m_position * 5));
			spin->addScatter(scatterPositions, 0, 0, false, EVT_FREE_GAMES, spinCount);
       		incrementFreeSpins(spinCount);
			++gbit;
		}
		setGameModeId(MODE_FREE_SPIN);
	}
	else
	{
		if (gbReel0Counted)
		{
			spin->addScatter(0, 0, 0, false, EVT_FEATURE_NEAR_MISS, 0);
		}
	}
	list.clear();
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldbeardGuts::isValidGuts()
///
/// @return	 bool8      True if gut is valid.
///
/// This helper method is used to the current gut ID is valid.
////////////////////////////////////////////////////////////////////////////
bool8
GoldbeardGuts::isValidGuts()
{
    return (getGutsId() >= 400 && getGutsId() < 500);
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldbeardGuts::getGameModeMultiplierAndNoteId()
///
/// @param   nGameModeMultiplier	
/// @param   nNoteId
///
/// @return	 void
///
/// This helper method is used to the current gut ID is valid.
////////////////////////////////////////////////////////////////////////////
void
GoldbeardGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier, uint8& nNoteId )
{
    if ( getGameModeId() == MODE_FREE_SPIN )
    {
        nGameModeMultiplier = MULTIPLIER_FREE_SPIN;
        nNoteId = NOTE_FREE_SPIN_3X;
    }
    else
    {
        SlotGuts::getGameModeMultiplierAndNoteId( nGameModeMultiplier, nNoteId );
    }

}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldbeardGuts::getFreeSpins()
///
/// @return	 int32      2,3,4 to denote the numnber of free spins one 
///						Goldbeard symbol can award.
///
/// This helper method is used to get the number of free spins for one
/// Goldbeard icon.
////////////////////////////////////////////////////////////////////////////
int32
GoldbeardGuts::getFreeSpins()
{
	int32 i = 0;
	static uint32 spin[][2] = {
		{2,18},
		{3,59},
		{4,99},
	};

	uint32 randomValue = getrand() % 100;

	while (randomValue > spin[i][1])
	{
		++i;
	}
	return spin[i][0];
}


////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	Debugging code
//
////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldbeardGuts::preSpinClassifyResults()
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This method is overridden in debug spins mode to alter the reel stops.
////////////////////////////////////////////////////////////////////////////
void GoldbeardGuts::preSpinClassifyResults( SlotSpin* spin )
{
	SlotGuts::preSpinClassifyResults(spin);
	return;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 GoldbeardGuts::Debug_SetLoserStops( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// Base class override, returns a losing spin triggered by the debug tool
////////////////////////////////////////////////////////////////////////////
void GoldbeardGuts::Debug_SetLoserStops( uint8* pStops )
{
	pStops[0]=0;
	pStops[1]=3;
	pStops[2]=0;
	pStops[3]=0;
	pStops[4]=3;
}